// specification: http://chessprogramming.wikispaces.com/Algebraic+Chess+Notation
package lan

import (
	b "code.google.com/p/gochess/board"
	"code.google.com/p/gochess/notation/san"
	pos "code.google.com/p/gochess/position"
	"errors"
	"fmt"
	"strings"
)

const enPassantNotation = "e.p."

var unused = []string{enPassantNotation, "+", "++", "=", "#"}

func removeUnusedStuff(notation string) string {

	for i := range unused {
		notation = strings.Replace(notation, unused[i], "", -1)
	}
	return strings.TrimSpace(notation)

}

func ParseMove(p *pos.Position, notation string) (pos.Move, error) {

	if notation == "0-0" || notation == "O-O" {
		return pos.NewCastling(p.SideToMove(), pos.CastlingShort), nil
	}

	if notation == "0-0-0" || notation == "O-O-O" {
		return pos.NewCastling(p.SideToMove(), pos.CastlingLong), nil
	}
	notation = strings.TrimSpace(removeUnusedStuff(notation))

	var err error
	var start, dst b.Square
	switch len(notation) {
	case 5:
		if start, err = san.ParseSquare(notation[:2]); err != nil {
			return pos.NoMove, err
		}
		if dst, err = san.ParseSquare(notation[3:5]); err != nil {
			return pos.NoMove, err
		}
		if dst == p.EnPassantTarget() {
			return pos.NewEnPassant(start, dst), nil
		}
		return pos.NewMove(start, dst), nil
	case 6:
		// piece move or promotion
		if _, err := san.ParsePiece(notation[:1]); err == nil {
			// first letter is a piece -> piece move
			if start, err = san.ParseSquare(notation[1:3]); err != nil {
				return pos.NoMove, err
			}
			if dst, err = san.ParseSquare(notation[4:6]); err != nil {
				return pos.NoMove, err
			}
			return pos.NewMove(start, dst), nil

		}
		// promotion
		if start, err = san.ParseSquare(notation[:2]); err != nil {
			return pos.NoMove, err
		}
		if dst, err = san.ParseSquare(notation[3:5]); err != nil {
			return pos.NoMove, err
		}
		promoted, err := san.ParsePiece(notation[5:])
		if err != nil {
			return pos.NoMove, errors.New("illegal promoted piece")
		}
		return pos.NewPromotion(start, dst, promoted), nil
	default:
		return pos.NoMove, errors.New("invalid notation, too many or too few characters.")
	}
}

func SprintMove(p *pos.Position, move pos.Move) string {
	if move.Castling() != pos.NoCastling {
		notation := "0-0"
		if move.Castling() == pos.CastlingLong {
			notation += "-0"
		}
		return notation
	}
	var ep string
	if move.CapturesEnPassant() {
		ep = enPassantNotation
	}
	sep := "-"
	if p.Get(move.Destination()) != pos.NoPiece {
		sep = "x"
	}
	return fmt.Sprint(san.SprintPiece(p.Get(move.Start()).Type()),
		san.SprintSquare(move.Start()), sep,
		san.SprintSquare(move.Destination()), san.SprintPiece(move.Promotion()), ep)
}
